/*******************************************************************************
 * Copyright (C) 2018-2020 CAROTA Technology Crop. <www.carota.ai>.
 * All Rights Reserved.
 *
 * Unauthorized using, copying, distributing and modifying of this file,
 * via any medium is strictly prohibited.
 *
 * Proprietary and confidential.
 ******************************************************************************/

package com.sun.dailyprj.pki;

import android.util.Base64;

import com.sun.dailyprj.util.Logger;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.util.Store;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;

import javax.crypto.Cipher;

public class PKCSUtil {

    private String ALGORITHMSTR = "RSA/NONE/PKCS1Padding";
    private String ALGORITHMSTR_ECB = "RSA/ECB/PKCS1Padding";

    /**
     * 验证数字签名
     *
     * @param signedData
     * @return
     */
    public static boolean signedDataVerify1(byte[] signedData) {
        boolean verifyRet = true;
        try{
            // 新建PKCS#7签名数据处理对象
            CMSSignedData sign = new CMSSignedData(signedData);
            if(sign.isDetachedSignature()){

            }

            // 添加BouncyCastle作为安全提供
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            Store store = sign.getCertificates();
            SignerInformationStore signers = sign.getSignerInfos();
            Collection<SignerInformation> coll = signers.getSigners();
            Iterator<SignerInformation> it = coll.iterator();
            while(it.hasNext()) {
                SignerInformation signer = it.next();
                Collection certs = store.getMatches(signer.getSID());
                Iterator certIt = certs.iterator();
                X509CertificateHolder holder = (X509CertificateHolder)certIt.next();
                X509Certificate cert = new JcaX509CertificateConverter()./*setProvider("BC").*/getCertificate(holder);
                boolean result = signer.verify(new JcaSimpleSignerInfoVerifierBuilder()./*setProvider("BC").*/build(cert));
                if(result) {
                    System.out.println("ok");
                    CMSProcessable sc = sign.getSignedContent();
                    byte[] data = (byte[])sc.getContent();
                    System.out.println("oragin content: "+ Bytes2HexString(Base64.decode(data, Base64.DEFAULT)) + " ; length = " + data.length);
                }

            }


            // 获得签名者信息
//            SignerInformationStore signers = sign.getSignerInfos();
//            Collection c = signers.getSigners();
//            Iterator it = c.iterator();
//
//            // 当有多个签名者信息时需要全部验证
//            while (it.hasNext()) {
//                SignerInformation signer = (SignerInformation) it.next();
//
//                // 证书链
//                Collection certCollection = certs.getMatches(signer.getSID());
//                Iterator certIt = certCollection.iterator();
//                X509CertificateHolder cert = (X509CertificateHolder) certIt
//                        .next();
//
//                // 验证数字签名
//                verifyRet = signer.verify(new JcaSimpleSignerInfoVerifierBuilder()
//                        /*.setProvider("BC")*/.build(cert));
//            }

        } catch (Exception e) {
            verifyRet = false;
            e.printStackTrace();
            System.out.println("验证数字签名失败");
        }
        return verifyRet;
    }



    /**
     * 验证数字签名
     *
     * @param signedData
     * @return
     */
    public static boolean signedDataVerify(byte[] signedData, String sha256) {
        boolean verifyRet = true;
        try{
            // 新建PKCS#7签名数据处理对象
            CMSSignedData sign = new CMSSignedData(signedData);
            if(sign.isDetachedSignature()){
                Logger.debug("sign is detach");
            }
            // 添加BouncyCastle作为安全提供
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            // 获得证书信息
            Store certs = sign.getCertificates();
            System.out.println("Store:" + certs.toString());
            Logger.debug("store:" + certs.toString());
            Logger.debug("signedContent:" + sign.getSignedContent().toString());
            Logger.debug("signedContent:" + sign);

            // 获得签名者信息
            SignerInformationStore signers = sign.getSignerInfos();
            Collection c = signers.getSigners();
            Iterator it = c.iterator();

            // 当有多个签名者信息时需要全部验证
            while (it.hasNext()) {
                SignerInformation signer = (SignerInformation) it.next();
                // 证书链
                Collection certCollection = certs.getMatches(signer.getSID());
                Iterator certIt = certCollection.iterator();
                X509CertificateHolder cert = (X509CertificateHolder) certIt.next();
                Logger.debug("cert:" + cert.toString());
                Logger.debug("cert.Signature:" + EncryptHelper.bytesToHexString(cert.getSignature()));
                Logger.debug("cert.version:" + cert.getVersionNumber());
                Logger.debug("cert.after:" + FormatUtil.formatDate(cert.getNotAfter()));
                Logger.debug("cert.before:" + FormatUtil.formatDate(cert.getNotBefore()));
                Logger.debug("cert.isValidOn:" + cert.isValidOn(new Date()) + " date = " + new Date());//证书有效期校验
                Logger.debug("cert.isValidOn:" + cert.getSignatureAlgorithm().getAlgorithm().toString());
                Logger.debug("cert.isValidOn:" + cert.getSignatureAlgorithm().toString());

                CMSSignedData s = new CMSSignedData(signedData);
                byte[] bSignSHA = (byte[]) s.getSignedContent().getContent();
                Logger.debug("md5: " + EncryptHelper.bytesToHexString(bSignSHA));
                Logger.debug("sha256:" + sha256);

                CMSProcessable signedContent = s.getSignedContent() ;
                byte[] originalContent = (byte[]) signedContent.getContent();
                Logger.debug("originalContent = " + EncryptHelper.bytesToHexString(originalContent));  //原sha256值，签名内容做了encode

                if(!sha256.equalsIgnoreCase(EncryptHelper.bytesToHexString(bSignSHA))) {
                    Logger.error("sha256 not same");
                    return false;
                }

                // 验证数字签名
                verifyRet = signer.verify(new JcaSimpleSignerInfoVerifierBuilder()
                        /*.setProvider("BC")*/.build(cert));
            }

        } catch (Exception e) {
            verifyRet = false;
            e.printStackTrace();
            System.out.println("验证数字签名失败");
        }
        return verifyRet;
    }

    public PKCSUtil() {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    private final static byte[] hex = "0123456789ABCDEF".getBytes();
    public static String Bytes2HexString(byte[] b) {
        byte[] buff = new byte[2 * b.length];
        for (int i = 0; i < b.length; i++) {
            buff[2 * i] = hex[(b[i] >> 4) & 0x0f];
            buff[2 * i + 1] = hex[b[i] & 0x0f];
        }
        return new String(buff);
    }

    public void testPrivateKey(X509CertificateHolder cert) throws Exception {
        String priKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL5o5kuY6LOQrfbmhHpKS0pqV3phJHylhIVhuKicmOJAq2kWMoRoCwGSIaPxY8YMw0mtgZ7NW8ALQ9BhvGp1uPHTJtDomVP+fOQsgBvNCOhOFLc9AOOxb+AF4QuSBjhUiuoMHxU1g2iECDb3NoUA/dsWSmMXBxy33dzvRm8vybPrAgMBAAECgYBVGTjjzIEjz6OQV1IZ/Z5Msd5K2aOe+bKSkiwfX22MoO561urY9k8E8rSKOtYmq4mUIjFuMcWxvNcgCK5WvipbUrYaGI1wTza34ncxO7rm7/mYB1BPhX+d5lPCTNKhYix7JlDGwaC/npxQJtR9FalhxFIU+Lmr2JZN4I3swDcikQJBAPwifquvVJ75TV/Js5xGpF5E4T8t9z8O3ceQfmszglv4hXuJJLKd2UFSa2bWGP3z0x2t3qX4ZbkJ9qUrFEsUIycCQQDBVCodYi9eVXdcD0Mosv/KZjO2mx51tS6XczWfUxoyRpYdWxLfyq5vBgGEEJt4QipkgGXKnwuUppGkXBdHMdOdAkABHKHUXfyQiublcj1Bhio5ZDJeFfTOKWGe/KsiC+MaRrlH9y3bP8jyecuRc4Y+sHGQ4vBlaPgB3eJhjhQT1K3nAkB2xoa5VsFTa57RaG8SaibM6s2KuvKTzqS5V4byQ9QsX0GK95E4/QT+IOp9gNaDo+L3rArd2aj7wvpnyExk6S/hAkEAxsFtWDChCZmt62vRmz3mmrtq9scg4LplA3U0vN2glv+lc+OoRQlG0lCRFak9BH0EWqbntREeRRMn6TOI0QZKYw==";
        String text = "raetest";


        // 加载公钥
        PKCS8EncodedKeySpec data = new PKCS8EncodedKeySpec(Base64.decode(priKey.getBytes(), Base64.DEFAULT));
        KeyFactory factory = KeyFactory.getInstance("RSA");
        PrivateKey key = factory.generatePrivate(data);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
//        cipher.init(Cipher.ENCRYPT_MODE, cert);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encryptData = cipher.doFinal(text.getBytes());
        String encrypt = Base64.encodeToString(encryptData, Base64.DEFAULT);

    }


}
